<template>
    <div>
<!--        filter:<pre>{{filter}}</pre>-->
<!--        nodes:<pre>{{filter.nodes}}</pre>-->
<!--        lineRelation:<pre>{{filter.lineRelation}}</pre>-->
        <el-button type="primary" @click="toLoadData">加载数据</el-button>
        <el-form label-width="150px" >
            <el-form-item label="测试用例名称：">
                <el-input v-model="filter.caseName"></el-input>
            </el-form-item>
            <el-form-item label="类型：">
                <el-radio-group v-model="filter.type">
                    <el-radio label="prim">普里姆</el-radio>
                    <el-radio label="kruskal">克鲁斯卡尔</el-radio>
                </el-radio-group>
            </el-form-item>
            <el-form-item label="节点数量：">
                <el-input-number v-model="filter.nodeSize" :min="1" :max="1000" :step="1" @change="initNodes"></el-input-number>
            </el-form-item>
            <el-form-item label="节点关系：">
                <el-table size="mini"
                        :data="filter.nodeRelation"
                        style="width: 100%">
                    <el-table-column
                            type="index"
                            width="50">
                    </el-table-column>
                    <el-table-column
                            prop="start"
                            label="开始节点"
                            width="180">
                        <template slot-scope="scope">
                            <el-select v-model="scope.row.start" placeholder="请选择" style="width: 100px;" @change="initNodes">
                                <el-option
                                        v-for="item in filter.options"
                                        :key="item"
                                        :label="item"
                                        :value="item">
                                </el-option>
                            </el-select>
                        </template>
                    </el-table-column>
                    <el-table-column
                            prop="stop"
                            label="结束节点"
                            width="180">
                        <template slot-scope="scope">
                            <el-select v-model="scope.row.stop" placeholder="请选择" style="width: 100px;" @change="initNodes">
                                <el-option
                                        v-for="item in filter.options"
                                        :key="item"
                                        :label="item"
                                        :value="item">
                                </el-option>
                            </el-select>
                        </template>
                    </el-table-column>
                    <el-table-column
                            prop="weight"
                            width="200"
                            label="权重">
                        <template slot-scope="scope">
                            <el-input-number v-model="scope.row.weight" :min="1" :max="1000" :step="1" @change="initNodes"></el-input-number>
                        </template>
                    </el-table-column>
                    <el-table-column label="操作">
                        <template slot-scope="scope">
                            <i v-if="scope.$index != 0" class="el-icon-top" style="margin-left:5px;cursor: pointer;" @click="moveUp(scope.$index)"></i>
                            <i v-if="scope.$index != filter.nodeRelation.length - 1" class="el-icon-bottom" style="margin-left:5px;cursor: pointer;" @click="moveDown(scope.$index)"></i>
                            <i class="el-icon-delete" style="margin-left:15px;cursor: pointer" @click="delRelation(scope.$index)"></i>
                        </template>
                    </el-table-column>
                </el-table>
                <el-row style="margin-top:10px;">
                    <el-button type="primary" @click="addRelation">添加</el-button>
                    <el-button type="primary" @click="calc" :loading="loading">计算</el-button>
                    <el-button type="primary" @click="toDownload">下载测试数据</el-button>
                    <el-button type="primary" @click="showStepByStep">分步演示</el-button>
                </el-row>
            </el-form-item>
            <el-form-item label="结果：">
                <el-table show-summary :summary-method="getSummaries"
                        :data="filter.result"
                        style="width: 100%">
                    <el-table-column
                            type="index"
                            width="50">
                    </el-table-column>
                    <el-table-column
                            prop="start"
                            label="开始节点"
                            width="180">
                        <template slot-scope="scope">
                            {{scope.row[0]}}
                        </template>
                    </el-table-column>
                    <el-table-column
                            prop="start"
                            label="结束节点"
                            width="180">
                        <template slot-scope="scope">
                            {{scope.row[1]}}
                        </template>
                    </el-table-column>
                    <el-table-column
                            prop="start"
                            label="权重"
                            width="180">
                        <template slot-scope="scope">
                            {{scope.row[2]}}
                        </template>
                    </el-table-column>
                </el-table>
            </el-form-item>
        </el-form>

        <div style="border: 3px solid #21f374;">
            <v-stage ref="stage" :config="stageSize">
                <v-layer ref="layer">
                    <template  v-for="(relation) in filter.lineRelation">
                        <v-line :key="relation.index" :config="{
                            points: relation.points,
                            stroke: relation.color,
                            strokeWidth: relation.strokeWidth,
                          }"/>
                    </template>

                    <template  v-for="(weightObj) in filter.weightLabels">
                        <v-text :key="'weight_' + weightObj.index"
                                :config="{
                                    text: weightObj.weight,
                                    x: weightObj.x,
                                    y: weightObj.y,
                                    fontSize: 24,
                                    stroke: 'purple',
                              }"
                        />
                    </template>

                    <template  v-for="(node) in filter.nodes">
                        <v-circle :key="'circle_' + node.label" :config="{x: node.x + 5, y: node.y + 5, radius: 25, fill: 'gray'}"/>

                        <v-text :key="node.label" ref="textNode"
                                @dragstart="(evt) => handleDragStart(node, evt)"
                                @dragend="(evt) => handleDragEnd(node, evt)"
                                @mouseover="mouseover"
                                @mouseout="mouseout"
                                :config="{
                                text: node.label,
                                x: node.x - 5,
                                y: node.y - 5,
                                fontSize: 30,
                                draggable: true,
                                fill: node.isDragging ? 'green' : 'purple',
                              }"
                        />

                    </template>
                </v-layer>
            </v-stage>
        </div>

        <el-dialog
                title="数据"
                :visible.sync="dialogVisible"
                width="30%">
            <span>
                <el-input
                        type="textarea"
                        :autosize="{ minRows: 3, maxRows: 25}"
                        placeholder="请粘贴内容"
                        v-model="sourceFormDataStr">
                </el-input>
            </span>
            <span slot="footer" class="dialog-footer">
            <el-button @click="dialogVisible = false">取 消</el-button>
            <el-button type="primary" @click="toApplySourceData">确 定</el-button>
          </span>
        </el-dialog>
    </div>
</template>

<script>
    /* eslint-disable */
    import FileSaver from 'file-saver'
    import lodash from 'lodash'
    import axios from "axios";

    const width = window.innerWidth;
    export default {
        name: "graph1",
        data() {
            return {
                loading: false,
                dialogVisible: false,
                sourceFormDataStr: null,
                filter: {
                    caseName: '图论测试用例1',
                    type: 'prim',
                    nodeSize: 5,
                    nodeRelation: [
                        // {start: 'A', stop: 'B', weight: 5},
                        // {start: 'A', stop: 'C', weight: 7},
                        // {start: 'B', stop: 'C', weight: 6},
                        // {start: 'B', stop: 'D', weight: 7},
                        // {start: 'C', stop: 'D', weight: 7},
                        // {start: 'C', stop: 'E', weight: 7},
                        // {start: 'D', stop: 'E', weight: 7},
                    ],
                    nodes: [],
                    options: [], //
                    lineRelation: [],
                    weightLabels: [],
                    result: [],
                },
            }
        },
        methods: {
            moveUp(index) {
                let tmpNodeRelationList = lodash.clone(this.filter.nodeRelation)
                let prevElm = tmpNodeRelationList[index - 1]
                let currentElm = tmpNodeRelationList[index]
                tmpNodeRelationList[index - 1] = currentElm
                tmpNodeRelationList[index] = prevElm

                this.filter.nodeRelation = tmpNodeRelationList
            },
            moveDown(index) {
                let tmpNodeRelationList = lodash.clone(this.filter.nodeRelation)
                let nextElm = tmpNodeRelationList[index + 1]
                let currentElm = tmpNodeRelationList[index]
                tmpNodeRelationList[index + 1] = currentElm
                tmpNodeRelationList[index] = nextElm

                this.filter.nodeRelation = tmpNodeRelationList
            },
            toApplySourceData() {
                let sourceFormData = null
                try {
                    sourceFormData = JSON.parse(this.sourceFormDataStr)
                    // console.log('sourceFormData:', sourceFormData)
                    this.filter = sourceFormData
                    this.dialogVisible = false
                } catch (e) {
                    sourceFormData = null
                    this.$message.error('不是有效数据')
                }
            },
            toLoadData() {
                this.dialogVisible = true
                this.sourceFormDataStr = ''
            },
            toDownload() {
                let blob = new Blob([JSON.stringify(this.filter,null,2)], {type: "text/plain;charset=utf-8"});
                let caseName = this.filter.caseName || '测试用例'
                caseName += "_" + this.filter.type
                FileSaver.saveAs(blob, caseName + ".txt");
            },
            getSummaries() {
                const sums = [];
                let weightSum = 0
                if (this.filter.result) {
                    this.filter.result.forEach(r => {
                        weightSum += r[2]
                    })
                }

                sums.push('合计')
                sums.push('')
                sums.push('')
                sums.push(weightSum)
                return sums
            },
            delRelation(index) {
                this.filter.nodeRelation.splice(index, 1)
                this.initNodes()
            },
            changeNodeNum() {
              let options = []
              for(let i = 0; i < this.filter.nodeSize; i++) {
                options.push(String.fromCharCode(65 + i))
              }
              this.filter.options = options

              for(let i = this.filter.nodeRelation.length - 1; i >= 0; i--) {
                  let relation = this.filter.nodeRelation[i]
                  // console.log('relation.start:', relation)
                  if ((relation.start && !options.includes(relation.start)) || (relation.stop && !options.includes(relation.stop))) {
                      this.filter.nodeRelation.splice(i, 1)
                  }
              }
            },
            mouseover() {
                document.body.style.cursor = 'pointer';
            },
            mouseout() {
                document.body.style.cursor = 'default';
            },
            handleDragStart(node) {
                node.isDragging = true;
            },
            handleDragEnd(node, evt) {
                // console.log('node:', node)
                // console.log('evt:', evt)
                node.isDragging = false;
                node.x = evt.target._lastPos.x <= 0 ? 5 : evt.target._lastPos.x
                node.y = evt.target._lastPos.y <= 0 ? 5 : evt.target._lastPos.y
                // console.log('node:', node)
                this.calcRelation()
                this.$localStorage.set('graph_nodes_query_condition', JSON.stringify(this.filter), 24 * 60 * 60 * 1000)
            },
            initNodes() {
              let historyNodeAxis = {}
              if (this.filter.nodes) {
                  this.filter.nodes.forEach(node => {
                      historyNodeAxis[node.label] = {
                          x: node.x,
                          y: node.y,
                      }
                  })
              }

              this.changeNodeNum()
              let nodes = []
              this.filter.options.forEach((option, index) => {
                  nodes.push({
                      label: option,
                      x: historyNodeAxis[option] && historyNodeAxis[option].x ? historyNodeAxis[option].x : 50 + index * 40,
                      y: historyNodeAxis[option] && historyNodeAxis[option].y ? historyNodeAxis[option].y : 50 + index * 40,
                      isDragging: false,
                  })
              })
              this.filter.nodes = nodes

              this.calcRelation()
            },
            calcRelation() {
                let lineRelation = []
                let weightLabels = []
                this.filter.nodeRelation.forEach((relation, index) => {
                    if (relation.start && relation.stop && relation.weight != null) {
                        let startNode = this.getNode(relation.start)
                        let stopNode = this.getNode(relation.stop)
                        // let startNodeX = startNode.x <= stopNode.x ? startNode.x + 15 : startNode.x - 10
                        // let startNodeY = startNode.y <= stopNode.y ? startNode.y + 15 : startNode.y - 10
                        // let stopNodeX = startNode.x <= stopNode.x ? stopNode.x - 10 : stopNode.x + 10
                        // let stopNodeY = startNode.y <= stopNode.y ? stopNode.y - 10 : stopNode.y + 10
                        let startNodeX = startNode.x
                        let startNodeY = startNode.y
                        let stopNodeX = stopNode.x
                        let stopNodeY = stopNode.y

                        lineRelation.push({
                            index: index,
                            start: startNode,
                            stop: stopNode,
                            points: [startNodeX, startNodeY, stopNodeX, stopNodeY],
                            color: 'black',
                        })

                        let weightX = (startNodeX + stopNodeX) / 2
                        let weightY = (startNodeY + stopNodeY) / 2
                        weightLabels.push({
                            index: index,
                            x: weightX,
                            y: weightY,
                            weight: relation.weight,
                        })
                    }
                })
                this.filter.lineRelation = lineRelation
                this.filter.weightLabels = weightLabels

                this.colorRelation()
            },
            getNode(label) {
              return this.filter.nodes.find(n => n.label == label)
            },
            addRelation() {
                this.filter.nodeRelation.push({
                    start: null,
                    stop: null,
                    weight: null,
                })
            },
            colorRelation() {
                if (this.filter.lineRelation) {
                    this.filter.lineRelation.forEach(lineRelation => {
                        lineRelation.color = 'black'
                    })

                    this.filter.lineRelation.forEach(lineRelation => {
                        for (let i = 0; i < this.filter.result.length; i++) {
                            if ((lineRelation.start.label == this.filter.result[i][0] && lineRelation.stop.label == this.filter.result[i][1]) || (lineRelation.start.label == this.filter.result[i][1] && lineRelation.stop.label == this.filter.result[i][0])) {
                                lineRelation.color = 'red'
                                lineRelation.strokeWidth = 5
                            }
                        }
                    })
                }
            },
            async calc() {
                for(let i = 1; i < this.filter.nodeRelation.length; i++) {
                    let nodeRelation = this.filter.nodeRelation[i]
                    for (let j = 0; j < i; j++) {
                        let nodeRelationJ = this.filter.nodeRelation[j]
                        let isEqual = (nodeRelation.start == nodeRelationJ.start && nodeRelation.stop == nodeRelationJ.stop)
                                || (nodeRelation.start == nodeRelationJ.stop && nodeRelation.stop == nodeRelationJ.start)
                        if (isEqual) {
                            this.$message.error("第" + (j + 1) + "行和第" + (i + 1) + "行数据重复，无法计算，请删除其中一个")
                            return
                        }
                    }
                }

                if (!this.filter.type) {
                    this.filter.type = 'prim'
                }

                let postData = {
                    type: this.filter.type,
                    nodes: this.filter.options,
                    relation: this.filter.nodeRelation,
                }
                this.loading = true
                try {
                    let response = await axios.post('/prim_kruskal', postData)
                    let responseData = response.data
                    // console.log('responseData:', responseData)
                    this.filter.result = responseData
                } catch (e) {
                    this.filter.result = []
                }
                this.loading = false

                this.colorRelation()
            },
            showStepByStep() {
                if (this.filter.lineRelation) {
                    this.filter.lineRelation.forEach(lineRelation => {
                        lineRelation.color = 'black'
                        lineRelation.strokeWidth = 1
                    })

                    let index = 1
                    for (let i = 0; i < this.filter.result.length; i++) {
                        this.filter.lineRelation.forEach(lineRelation => {
                            if ((lineRelation.start.label == this.filter.result[i][0] && lineRelation.stop.label == this.filter.result[i][1]) || (lineRelation.start.label == this.filter.result[i][1] && lineRelation.stop.label == this.filter.result[i][0])) {
                                setTimeout(() => {
                                    lineRelation.color = 'red'
                                    lineRelation.strokeWidth = 5
                                }, 1000 * index++)
                            }
                        })
                    }


                }
            },
        },
        computed: {
            height() {
                let height = 300
                this.filter.nodes.forEach(node => {
                    if(node.y + 50 > height) {
                        height = node.y + 50
                    }
                })
                return height
            },
            stageSize() {
                return {
                    width: width,
                    height: this.height
                }
            },
        },
        mounted() {
            let cachedCondition = this.$localStorage.get('graph_nodes_query_condition')
            let cacheUseful = false
            if (cachedCondition) {
                let backupFilterData = lodash.clone(this.filter)
                try {
                    this.filter = JSON.parse(cachedCondition)
                    cacheUseful = true
                } catch (e) {
                    this.filter = backupFilterData
                }
            }

            if (!cacheUseful) {
                this.initNodes()
            }

        }
    }
</script>

<style scoped>

</style>
